package com.hontech.bread.store

import android.widget.ImageView
import com.hontech.bread.R
import com.hontech.bread.api.downloadImage
import com.hontech.bread.utils.decodeBitmap
import com.hontech.bread.utils.log
import com.hontech.bread.utils.runCPU
import com.hontech.bread.utils.runIO
import com.hontech.bread.utils.runOnUiCatchAny
import com.hontech.bread.utils.stringById
import com.hontech.bread.utils.toRounded
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileInputStream

class StoreProductExt(
    val productId: String,
    val name: String,
    val price: Int,
    val heatTime: Int,
    val expiration: Long, // ${stringById(R.string.t1733460848_311)} ${stringById(R.string.t1733460848_312)}
    val imageUrl: String,
)

class StoreProduct(
    val productId: String,
    val name: String,
    val price: Int,
    val heatTime: Int,
    val expiration: Long, // ${stringById(R.string.t1733460848_313)} ${stringById(R.string.t1733460848_314)}
    val image: ByteArray
) {

    companion object {

        const val TB_NAME = "tb_store_product"
        const val CREATE_SQL = "CREATE TABLE IF NOT EXISTS $TB_NAME (" +
                "id INTEGER PRIMARY KEY AUTOINCREMENT, " +
                "product_id TEXT NOT NULL, " +
                "name TEXT NOT NULL, " +
                "price INTEGER NOT NULL, " +
                "heat_time INTEGER NOT NULL, " +
                "expiration INTEGER NOT NULL, " +
                "image BLOB NOT NULL, " +
                "image_url TEXT NOT NULL, " +
                "update_seq INTEGER NOT NULL, " +
                "UNIQUE(product_id)" +
                ")"

        const val DROP_SQL = "DROP TABLE IF EXISTS $TB_NAME"

        private val updateMutex = Mutex()

        suspend fun update(list: List<StoreProductExt>) {
            updateMutex.withLock { updateImpl(list) }
        }

        private suspend fun updateImpl(list: List<StoreProductExt>) {

            val seq = runCPU {
                val cursor = Store.db.rawQuery("SELECT update_seq FROM $TB_NAME LIMIT 1", arrayOf())
                val seq = cursor.use {
                    if (cursor.moveToNext()) {
                        cursor.getLong(0) + 1
                    } else {
                        0
                    }
                }
                seq
            }

            log("current seq:${seq}")

            for (product in list) {

                val imageUrl = runCPU {
                    val cursor = Store.db.rawQuery(
                        "SELECT image_url FROM $TB_NAME WHERE product_id = ?",
                        arrayOf(product.productId)
                    )
                    cursor.use {
                        if (cursor.moveToNext()) {
                            cursor.getString(0)
                        } else {
                            null
                        }
                    }
                }

                if (imageUrl == null) { // ${stringById(R.string.t1733460848_315)}
                    log("${stringById(R.string.t1733460848_316)}:${product.name}")

                    val image = downloadImage(product.imageUrl)

                    runCPU {
                        Store.db.execSQL(
                            "INSERT INTO " +
                                    "$TB_NAME (product_id, name, price, heat_time, expiration, image, image_url, update_seq) " +
                                    "VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
                            arrayOf(
                                product.productId,
                                product.name,
                                product.price,
                                product.heatTime,
                                product.expiration,
                                image,
                                product.imageUrl,
                                seq
                            )
                        )
                    }
                } else {
                    log(stringById(R.string.t1733460848_317))

                    if (imageUrl != product.imageUrl) {
                        log("image_url ${stringById(R.string.t1733460848_318)}")

                        val image = downloadImage(product.imageUrl)
                        runCPU {
                            Store.db.execSQL(
                                "UPDATE $TB_NAME " +
                                        "SET name = ?, price = ?, heat_time = ?, expiration = ?, image = ?, image_url = ?, update_seq = ? " +
                                        "WHERE product_id = ?",
                                arrayOf(
                                    product.name,
                                    product.price,
                                    product.heatTime,
                                    product.expiration,
                                    image,
                                    product.imageUrl,
                                    seq,
                                    product.productId
                                )
                            )
                        }
                    } else {
                        log("image_url ${stringById(R.string.t1733460848_319)}")

                        runCPU {
                            Store.db.execSQL(
                                "UPDATE $TB_NAME " +
                                        "SET name = ?, price = ?, heat_time = ?, expiration = ?, update_seq = ? " +
                                        "WHERE product_id = ?",
                                arrayOf(
                                    product.name,
                                    product.price,
                                    product.heatTime,
                                    product.expiration,
                                    seq,
                                    product.productId
                                )
                            )
                        }
                    }
                }
            }

            runCPU {
                Store.db.execSQL("DELETE FROM $TB_NAME WHERE update_seq != ?", arrayOf(seq))
            }
        }

        suspend fun query() = runCPU {
            val cursor = Store.db.rawQuery(
                "SELECT product_id, name, price, heat_time, expiration, image " +
                        "FROM $TB_NAME",
                arrayOf()
            )
            val list = ArrayList<StoreProduct>()
            cursor.use {
                while (cursor.moveToNext()) {
                    list.add(
                        StoreProduct(
                            cursor.getString(0),
                            cursor.getString(1),
                            cursor.getInt(2),
                            cursor.getInt(3),
                            cursor.getLong(4),
                            cursor.getBlob(5)
                        )
                    )
                }
            }
            list
        }
    }

}


fun ImageView.setProductImage(product: StoreProduct) {
    this.setTag(R.id.imageId, product.productId)
    post {
        runOnUiCatchAny {
            val w = width
            val h = height
            val bitmap = runCPU { decodeBitmap(product.image, w, h).toRounded(10, w, h) }
            if (getTag(R.id.imageId) != product.productId) {
                return@runOnUiCatchAny
            }
            setImageBitmap(bitmap)
        }
    }
}

fun ImageView.setImageWithByteArray(buf: ByteArray) {
    post {
        runOnUiCatchAny {
            val w = width
            val h = height
            val bitmap = runCPU { decodeBitmap(buf, w, h).toRounded(10, w, h) }
            setImageBitmap(bitmap)
        }
    }
}

suspend fun ImageView.setImageWithFile(file: File) {
    val data = runIO {
        val input = FileInputStream(file)
        val out = ByteArrayOutputStream()
        input.use {
            val buf = ByteArray(1024)
            while (true) {
                val n = input.read(buf)
                if (n <= 0) {
                    break
                }
                out.write(buf, 0, n)
            }
        }
        out.toByteArray()
    }
    setImageWithByteArray(data)
}













